Verifying Design with Proof Scores
نویسندگان
چکیده
Verifying design instead of code can be an effective and practical approach to obtaining verified software. This paper argues that proof scores are an attractive method for verifying design, in that they achieve a balance in which the respective capabilities of humans and machines are utilized optimally. 1 Verifying Code or Design Although creation of a verifying compiler is a difficult challenge, recent developments suggest that there are ways to make it easier. Systems that generate lexical analyzers and parsers already have a long history (e.g. Lex and Yacc), and recent work of Sorin Lerner [23] shows that the same can be done for compiler backends; there is also work suggesting that code generation modules can be automatically generated (e.g. using intermediate languages). Unfortunately, a great number of different compilers are needed in today’s software world, and the underlying machine architectures are evolving, as are the languages, so it would be difficult to create verifying compilers for all useful combinations of language and platform, and code verification for such tools still remains very difficult. Major impediments include the unsolvability of discovering loop invariants, the potential unsolvability of loop once they are found, and the further difficulties raised by interactivity, nondeterminism, concurrency, distribution, active agents, and unreliable communication. A long term approach is to use high level, application specific source languages, in order to greatly simplify source program verification by eliminating many obscure features of current languages. In the meantime, a currently feasible approach is to verify the design of software, instead of its code; experience shows that design verification often leads to better design, and nearly always leads to greater conceptual clarity. An aditional motivation is that the main sources of errors in software are in areas other than code, namely, requirements, specification, and design. 2 The Proof Score Approach The goal of verification in software engineering is to increase confidence in the correctness of computerbased systems. For software verification to be genuinely useful, careful account must be taken of the context of actual use, including the goals of the system, the underlying hardware, and the capabilities and culture of users. Absolute certainty is not achievable in real applications, due to the uncertainties inherent in implementation and use, e.g., breakdowns in physical infrastructure (such as cables and computers), errors by human operators, and flaws in connected systems (e.g., operating systems and databases). Fully automatic theorem provers often fail to convey an understanding of their proofs, and they are generally unhelpful when they fail because of user errors in specifications or goals, or due to the lack of a necessary lemma or case split (both of which are very common in practice). It follows that one should seek to make optimal use of the respective abilities of humans and computers, so that computers do the tedious formal calculations, and humans do the high level planning; the tradeoff between detail and comprehension should also be carefully balanced. Proof scores are a central concept in our approach to meeting these goals; proof scores are instructions to a proof engine, such that when they are executed (or “played”), if everything evaluates as expected, then a desired theorem is proved. Proof scores hide the detailed calculations done by machines, while revealing the proof plan created by humans. Although proof scores can be used to verify code in an imperative language (e.g., as in [20]), it generally makes more sense to verify design rather than code. These techniques differ from model checking [5] in their emphasis on re-usable designs (e.g., for protocols and other algorithms), which may be instantiated in code in many different ways, as well as in their ability to deal with systems that have an infinite number of states, and their natural affinity for abstraction. We have recognized that many attempts are done to use model checking techniques to prove designs or algorithms which are expressed as, for example, finite state transition systems. But they are usually expressed only using low-level data types and very close to program code. Besides, model checking only gives “yes” or “no with counter example”, and does not support interactive analyses or understandings of designs. Many proof scores have been written in CafeOBJ [6, 9] for verifying properties of distributed systems, especially distributed algorithms, component-based software, and security protocols [8, 27, 31, 32, 34]. Several auxiliary tools have been also been built to support this progress, including PigNose [25], Gateaux, Crème [26], and Kumo [19]. The facilities for behavioral (or observational) proof in CafeOBJ are important for verifying distributed systems, and its advanced module system can be used to express the structure of proofs as well as specifications. In addition, it provides a stable, portable, and reasonably efficient platform for the execution of proof scores, supporting not only term rewriting, but also reasoning in equational logic, rewriting logic, and basic hidden algebra [3]. BOBJ [17] has similar capabilities, featuring a powerful coinduction algorithm that has also been used to verify distributed systems [14]. The following principles can be seen as a requirements analysis for the proof score approach, based on the authors’ extensive experience using OBJ [10, 18], BOBJ, and CafeOBJ. Human Computer Interaction Since fully automatic theorem proving is often infeasible for system verification, it is desirable to integrate the human user in the best possible way: in particular, the proof plans or “scores” should be as readable as possible, and helpful feedback should be provided by machines to humans, in order to maximize their ability to contribute. Flexible but Clear Structure It is often desirable to arrange the parts of a verification so as to facilitate comprehension. For example, it is often helpful to state and use a result before it is proved, or even (during proof the planning process) before it is known to be true. Long sequences of proof parts can be difficult to understand, especially when there is no obvious immediate connection between two adjacent parts. But such discontinuities are rather common in published proofs, e.g., when a series of lemmas is proved before they are used in proving a main result. This implies that both subgoals and goal/subgoal relations should be very clear. Flexible Logic Although first order predicate logic is the dominant modern logical system, many other logics are used, and in particular, computer scientists have developed many new logics, e.g., for database systems, knowledge representation, and the semantic web; these include variants of propositional logic, modal logic, intuitionistic logic, higher order logic, and equational logic. It is desirable to be able to support as many of these as possible, as well as their combinations, within a single tool. Moreover, the necessary incompleteness of formal logics that have sufficient expressive power, means that users may want to incorporate new rules of inference “on the fly,” for example, to take advantage of a symmetry at the meta level to reduce the cases that need to be considered in a proof. It is often possible to simulate one logic within another, by imposing a suitable discipline on how its rules are used; in fact, this is precisely what proof scores accomplish. The choice of underlying basic logics for such a purpose is important in at least three dimensions: its efficiency, its simplicity and ease of use, and its ability to support other logics. We believe that equational logic and its variants are the most suitable for this purpose: Equational logics are relatively simple, have many decidable properties with associated efficient algorithms, are relatively easy to read and write, and can support reasoning in most other logics, e.g., by supplying appropriate definitions to an engine that can apply them by as rewrite rules. By contrast, higher order logic and type theory are much more complex, harder to read and write, harder to mechanize, and harder to reason with, for both humans and machines. Behavioral Logic Distributed systems consist of abstract machines in which states are hidden, but can be “observed” by certain “attribute” functions with values in basic data types (such as integer or boolean). Behavioral (also called observational) logic is a natural approach to verifying such systems. Three major approaches in this area are: coalgebra (e.g., see the overview [22]); the “observational logic” of Bidoit and Henniker [2, 21]; and hidden algebra [15, 7], on which our own work is based. CafeOBJ mechanizes the special (but common) case of coinduction in which the effects of methods (or actions) need not be considered for behavioral equivalence, i.e., for which s, s′ are behaviorally equivalent if a(s) = a(s′) for all applicable attributes a. More sophisticated models can be embedded within this framework, particularly the OTS (Obsevational Transition Systems) model [27] (the power of which is similar to that of unity [4]), and the TOTS (timed OTS) model [28], which provides a logical basis for verifying real time concurrent systems with CafeOBJ. 3 Development of Proof Scores If a specification is expressed as a set of equations and if the equations can be used as rewriting rules for getting a simplest form of a given expression, then the validity of a statement about the specification can be checked by getting a simplest form of a boolean expression for the statement. The word reduction is used for simplifying an expression by rewriting rules. If a reasoning process can be designed in such a way that all the tedious calculations are done by reductions, and all rules of inference are applied by setting up special contexts for such reductions, and if every reduction gives the expected result, then the desired theorm is proved. Several well polished small proof scores for data types appeared in OBJ already in 80’s, e.g., see [18]. For example, they use reductions to prove induction steps and bases, based on the structure of initial term algebras. Typical examples are proofs of associativity and commutativity of addition for Peano natural numbers, and the identity n× (n+ 1) = 2× (1 + 2 + · · ·+ n) for any natural number n. ¿From around 1997, the CafeOBJ group at JAIST [3] started to extend the proof score method (1) to apply to distributed and real-time systems, such as classical distributed (and/or real-time) algorithms, component-based software, railway signal systems, secure protocols, etc., (2) to make the method applicable to practical size problems, and (3) to automate the method. As a result, the proof score method using reduction (rewriting) has become a promising way to do serious proofs. From Static to Dynamic Systems Early proof scores in CafeOBJ included (1) equivalences of functions over natural numbers, (2) equivalences of functions over lists, (3) correctness of simple compilers from expressions to machine code for stack machines, etc. These small proof scores realized an almost ideal combination of high level planning and mechanical reduction. However, even for this class of problems, some non-trivial lemma discovery and/or case spliting is required. Dynamic systems (i.e. systems with changing states) are common in network/computer based systems, but there is no established methodology in algebraic specification for coping with this class of problems. The CafeOBJ language is designed for writing formal specifications of dynamic systems based on hidden algebra [6, 12, 9]. Many specifications and proof scores for dynamic systems have been done based on hidden algebra semantics, and OTS has been selected as a most promising model. OTS corresponds to a restricted class of hidden algebras, such that it is possible to write specifications for OTS in a fixed standard style that facilitates the development of specifications, and also helps in writing proof scores, since case splits can be suggested by the specifications. The followings publications show stages in the evolution of proof scores for dynamic systems: – Specifying and verifying mutual exclusion algorithms by incorporating the unity model [27]. – Introduction of a primitive version of OTS [29]. – Introduction of real-time features into OTS/CafeOBJ, and accompanying development of proof scores methodology [28, 11]. – A proper introduction of OTS/CafeOBJ and the related proof score writing method [30, 33]. – Examples of verifications with proof scores in OTS/CafeOBJ [31, 32, 34] (among others). From Explaining to Doing Proofs A major factor distinguishing the stages of evolution of proof scores is the extent of automation. This is a most important direction of evolution for proof scores, although full automation is not a goal. Automation by reduction is suitable for a mechanical calculation with a focused role and a clear meaning in the context of a larger reasoning process. Early proof scores assisted verification by doing reductions to prove necessary logical statements for a specification. It is intended to gradually codify as many kinds of logical statements as possible into reductions in CafeOBJ. Recently, a fully automatic verification method for a subset of OTS has been developed. This algorithm can be seen as an unification of several techniques for proof scores in OTS/CafeOBJ. The following publications show the stages of automation of proof scores: – Mainly used for writing formal specifications, but also for proof scores [27]. – Examples with sufficiently complete proof scores [31, 32, 34] (among others). – A different attempt for automatiing proof scores [25]. – A fully automatic (algorithmic) method of verification for OTS [26]. Environment for Proof Score Development The Kumo system [19, 13] provides the proof score approach with greater rigor and better support for proof debugging, although at the cost of learning to use an additional tool. Kumo generates a website, called a proofweb, for each proof attempt that it executes. This website has links to background tutorial material, including tutorial pages for each major proof method used, and for the less familiar mathematical theories used, such as hidden algebra. A somewhat similar experimental tool has been developed for generating and displaying proof scores [36]. 4 An Example of Proof Score in CafeOBJ: An Identify-Friend-or-Foe (IFF) Protocol This section gives a simple but non-trivial example of proof score in CafeOBJ to help readers get a more concrete idea of what proof score is. Let us consider an Identify-Friend-or-Foe (IFF) protocol, which is supposedly used to check if an agent is a member of a group. The IFF protocol can be described as follows: 1. Check p → q : r 2. Reply q → p : EK(r, q) We suppose that an agent belongs to only one group, a symmetric key is given to each group, whose members share the key, and keys are different from group to group. If an agent p wants to check if an agent q is a member of the p’s group, p generates a fresh random number r and sends it to q as a Check message. On receipt of the message, q replies to the message by sending the random number r received and the ID q, which are encrypted with the symmetric key K of the q’s group, to p as a Reply message. On receipt of the message, p tries to decrypt the ciphertext received with the symmetric key of the p’s group. If the decryption succeeds and the plaintext consists of r and q, then p concludes that q is a member of the p’s group. The protocol is supposed to have the property that if p receives a valid Reply message from q, q is always a member of the p’s group. The property is called the IFF property in this paper. 4.1 Modeling and Specification of the Protocol We suppose that the cryptosystem used is perfect, there is only one legitimate group, all members of the group are trustable, and there are also untrustable agents who are not members. Trustable agents exactly follow the protocol, but untrustable ones may do something against the protocol as well. The combination 4 This work used the Maude rewriting engine [24] because it provides faster associative and commutative rewriting. 5 The IFF protocol used in this paper is a modified version of the IFF system described in Subsect. 2.2.2 of [1]. and cooperation of untrustable agents is modeled as the most general intruder (or enemy). The enemy gleans as much information as possible from messages flowing in the network and fakes messages based on the gleaned information, provided that the enemy cannot break the perfect cryptosystem. We first describe the basic data types used to model the protocol. The visible sorts corresponding to the basic data types and the related operators (if any) are as follows: – sort Agent denotes agents; constant enemy denotes the enemy, – sort Key denotes symmetric keys; given an agent p, k(p) denotes the key of the p’s group; operator p returns the argument of k(p), – sort Rand denotes random numbers, and – sort Cipher denotes ciphertexts used in the protocol; given a key k, a random number r and an agent p, enc(k, r, p) denotes the ciphertext obtained by encrypting r and p with k; operators k, r and p return the first, second and third arguments of enc(k, r, p). In addition to those visible sorts, the built-in sort Bool denoting truth values is used. The two operators to denote the two kinds of messages are cm and rm, which are declared as op cm : Agent Agent Agent Rand -> Msg and op rm : Agent Agent Agent Cipher -> Msg , where Msg is the visible sort denoting messages. Operators crt, src and dst return the first, second and third arguments of each message; operator r returns the fourth argument of a Check message; operator c returns the fourth argument of a Reply message. Operators cm? and rm? check if a given message is a Check message and a Reply message, respectively. The first, second and third arguments of each of cm and rm mean the actual creator, the seeming sender and the receiver of the corresponding message. The first argument is meta-information that is only available to the outside observer and the agent that has sent the corresponding message, and that cannot be forged by the enemy, while the remaining arguments may be forged by the enemy. The network is modeled as a multiset of messages, which is used as the storage that the intruder can use. The network is also used as each agent’s private memory that reminds the agent to send messages, whose first arguments are the agent. Any message that has been sent or put once into the network is supposed to be never deleted from the network. Consequently, the emptiness of the network means that no messages have been sent. The enemy tries to glean two kinds of values from the network, which are random numbers and ciphertexts. The collections of these values gleaned by the intruder are denoted by operators rands and ciphers, which are declared as op rands : Network -> ColRands and op ciphers : Network -> ColCiphers , where Network is the visible sort denoting networks, ColRands is the visible sort denoting collections of random numbers, and ColCiphers is the visible sort denoting collections of ciphertexts. The two operators are defined in equations. ciphers is defined as follows: eq C \in ciphers(void) = false . ceq C \in ciphers(M,NW) = true if rm?(M) and C = c(M) . ceq C \in ciphers(M,NW) = C \in ciphers(NW) if not(rm?(M) and C = c(M)) . Constant void denotes the empty multiset and operator ‘,’ in M,NW denotes the data constructor of nonempty multisets. The equations say that a ciphertext C is available to the enemy iff there exists a Reply message, which includes C. rands is defined likewise. We describe the OTS SIFF modeling the protocol. The foundation behind the modeling is basically behavioral logic (precisely a restricted class of hidden algebras), but other logics such as the UNITY logic can be incorporated into the proof score approach flexibly and faithfully such as [35] thanks to the flexible logic capability of the CafeOBJ system. Two observations and five parametrized transitions are used. The two observations are denoted by observation operators nw and ur, which are declared as bop nw : Field -> Network and bop ur : Field -> URands , where Field is the hidden sort denoting the state space and URands is the visible sort denoting sets of random numbers. nw and ur are used to observe the network and the set of used random numbers. The five transitions are denoted by action operators sdcm, sdrm, fkcm1, fkrm1 and fkrm2, which are declared as follows: bop sdcm : Field Agent Agent Rand -> Field bop sdrm : Field Agent Msg -> Field bop fkcm1 : Field Agent Agent Rand -> Field bop fkrm1 : Field Agent Agent Cipher -> Field bop fkrm2 : Field Agent Agent Rand -> Field . The first two action operators formalize sending messages exactly following the protocol and the remaining the enemy’s faking messages. The action operators are defined in equations. sdrm is defined as follows: ceq nw(sdrm(F,P1,M1)) = rm(P1,P1,src(M1),enc(k(P1),r(M1),P1)) , nw(F) if c-sdrm(F,P1,M1) . eq ur(sdrm(F,P1,M1)) = ur(F) . ceq sdrm(F,P1,M1) = F if not c-sdrm(F,P1,M1) . c-sdrm(F,P1,M1) equals M1 \in nw(F) and cm?(M1) and P1 = dst(M1), which means that in state F, there exists a Check message M1 in the network, which is addressed to P1. If this condition holds, the Reply message denoted by rm(...) is put into the network nw(F). fkrm1 is defined as follows: ceq nw(fkrm1(F,P1,P2,C)) = rm(enemy,P1,P2,C) , nw(F) if c-fkrm1(F,P1,P2,C) . eq ur(fkrm1(F,P1,P2,C)) = ur(F) . ceq fkrm1(F,P1,P2,C) = F if not c-fkrm1(F,P1,P2,C) . c-fkrm1(F,P1,P2,C) equals C \in ciphers(nw(F)), which means that in state F, a ciphertext C is available to the enemy. The equations say that if a ciphertext C is available to the enemy, the enemy can fake and send a Reply message using C. The remaining three action operators are defined as follows:
منابع مشابه
Proof - Carrying Code . Design and Implementation
Proof-Carrying Code (PCC) is a general mechanism for verifying that a code fragment can be executed safely on a host system. The key technical detail that makes PCC simple yet very powerful is that the code fragment is required to be accompanied by a detailed and precise explanation of why it satisfies the safety policy. This leaves the code receiver with the simple task of verifying that the e...
متن کاملDesign and Implementation of a Proof-of-Concept MMORPG Using CSP and occam-π
We describe an experiment in the application of CSP and occam-π to the specification and implementation of a significant concurrent application. The utility of CSP for prototyping and verifying the complex interactions of a proof-of-concept multiplayer game is explored, as are several interesting new extensions to the occam language. Verifying the design with CSP is found to eliminate potential...
متن کاملTracking Design Changes with Formal Machine - Checked Proof
Designs are often modi ed for use in new circumstances. If formal proof is to be an acceptable veri cation methodology for industry, it must be capable of tracking design changes quickly. We describe our experiences formally verifying an implementation of an ATM network component, and on our subsequent veri cation of modi ed designs. Three of the designs veri ed are in use in a working network....
متن کاملVerifying Behavioural Specifications in CafeOBJ Environment
In this paper, we present techniques for automated verification of behavioural specifications using hidden algebra. Two non-trivial examples, the Alternating Bit Protocol and a snooping cache coherence protocol, are presented with complete specification code and proof scores for CafeOBJ verification system. The refinement proof based on behavioural coinduction is given for the first example, an...
متن کاملTracking Design Changes with Formal Verification
Designs are often modiied for use in new circumstances. If formal proof is to be an acceptable veriication methodology for industry , it must be capable of tracking design changes quickly. We describe our experiences formally verifying an implementation of an ATM network component, and on our subsequent veriication of modiied designs. Three of the designs veriied are in use in a working network...
متن کاملذخیره در منابع من
با ذخیره ی این منبع در منابع من، دسترسی به آن را برای استفاده های بعدی آسان تر کنید
عنوان ژورنال:
دوره شماره
صفحات -
تاریخ انتشار 2005